package mybatis.interceptor.example.aspect;

import lombok.extern.slf4j.Slf4j;
import mybatis.interceptor.example.interceptor.TpTenantReadInterceptor;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Plugin;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author guan.xin
 * @title MybatisInterceptorAspect
 * @description
 * @create 2022-04-21 14:23
 * @since JDK8
 */
@Slf4j
@Aspect
@Component
public class MybatisInterceptorAspect {

    private static final Map<String, Interceptor> CacheMybatisInterceptor = new ConcurrentHashMap<>(4);

    @PostConstruct
    public void init() {
        CacheMybatisInterceptor.put("PrimitiveTenantInterceptor", new TpTenantReadInterceptor());
    }

    @Pointcut("execution (* mybatis.interceptor.example.interceptor.PrimitiveTenantInterceptor.plugin(..))")
    public void pointcut() {
    }

//    @Before("pointcut()")
//    public void beforeAdvice() {
//        System.out.println("beforeAdvice...");
//    }
//
//    @After("pointcut()")
//    public void afterAdvice() {
//        System.out.println("afterAdvice...");
//    }

    @Around("pointcut()")
    public Object aroundAdvice(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        // CachingExecutor => DefaultParameterHandler => DefaultResultSetHandler => RoutingStatementHandler
        Object object = proceedingJoinPoint.getArgs()[0];
        if (object instanceof Executor) {
            Interceptor interceptor = CacheMybatisInterceptor.get(proceedingJoinPoint.getSignature().getDeclaringType().getSimpleName());
            log.info("将原始拦截器替换为：{}", interceptor.getClass().getSimpleName());
            return Plugin.wrap(object, interceptor);
        }
        return proceedingJoinPoint.proceed();
    }
}
